"use client";

import React, { useState, useMemo, useRef, useEffect } from "react";
import {
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
  type ColumnDef,
  type ColumnFiltersState,
} from "@tanstack/react-table";
import { cn } from "~/components/lib/utils";
import {
  Download,
  Filter,
  MoreHorizontal,
  RefreshCw,
  ExternalLink,
} from "lucide-react";
import { Slider } from "~/components/lib/ui/slider";

// Make the component generic to work with any type of vulnerability data
interface VulnerabilityTableProps<T> {
  columns: ColumnDef<T, any>[];
  data: T[];
  onRowClick?: (row: T) => void;
  onSelectionChange?: (selectedRows: T[]) => void;
  onGenerateReport?: (selectedRows: T[]) => void;
}

export function VulnerabilityTable<T extends { [key: string]: any }>({
  columns,
  data,
  onRowClick,
  onSelectionChange,
  onGenerateReport,
}: VulnerabilityTableProps<T>) {
  const [globalFilter, setGlobalFilter] = useState("");
  const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
  const [rowSelection, setRowSelection] = useState({});
  const [activeFilters, setActiveFilters] = useState<string[]>([]);
  const [showExportDropdown, setShowExportDropdown] = useState(false);
  const exportRef = useRef<HTMLDivElement>(null);

  // Track clicks outside of export dropdown
  useEffect(() => {
    function handleClickOutside(event: MouseEvent) {
      if (
        exportRef.current &&
        !exportRef.current.contains(event.target as Node)
      ) {
        setShowExportDropdown(false);
      }
    }

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, []);

  // Enable row selection by adding a selection column
  const selectionColumn: ColumnDef<T, any> = {
    id: "select",
    header: ({ table }) => (
      <div className="px-1">
        <input
          type="checkbox"
          className="h-4 w-4 rounded border-gray-300 text-violet-600 focus:ring-violet-500"
          checked={table.getIsAllPageRowsSelected()}
          ref={(input) => {
            if (input) {
              input.indeterminate =
                table.getIsSomePageRowsSelected() &&
                !table.getIsAllPageRowsSelected();
            }
          }}
          onChange={table.getToggleAllPageRowsSelectedHandler()}
        />
      </div>
    ),
    cell: ({ row }) => (
      <div className="px-1" onClick={(e) => e.stopPropagation()}>
        <input
          type="checkbox"
          className="h-4 w-4 rounded border-gray-300 text-violet-600 focus:ring-violet-500"
          checked={row.getIsSelected()}
          onChange={row.getToggleSelectedHandler()}
        />
      </div>
    ),
    enableSorting: false,
    enableGlobalFilter: false,
  };

  // Add selection column to columns array
  const columnsWithSelection = useMemo(() => {
    return [selectionColumn, ...columns];
  }, [columns]);

  const table = useReactTable({
    data,
    columns: columnsWithSelection,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    state: {
      globalFilter,
      columnFilters,
      rowSelection,
    },
    onColumnFiltersChange: setColumnFilters,
    onGlobalFilterChange: setGlobalFilter,
    onRowSelectionChange: (updater) => {
      setRowSelection(updater);
      if (onSelectionChange) {
        const newRowSelection =
          typeof updater === "function" ? updater(rowSelection) : updater;
        const selectedRowsArray = Object.keys(newRowSelection)
          .map((index) => {
            const idx = parseInt(index);
            return idx >= 0 && idx < data.length ? data[idx] : undefined;
          })
          .filter((item): item is T => item !== undefined);

        onSelectionChange(selectedRowsArray);
      }
    },
    initialState: {
      pagination: {
        pageSize: 10,
      },
      sorting: [
        {
          id: "severity",
          desc: true, // Sort severity high-to-low by default
        },
      ],
    },
    enableRowSelection: true,
  });

  // Handle search input
  const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
    const value = event.target.value;
    setGlobalFilter(value);
  };

  // Handle row click - open vulnerability details
  const handleRowClick = (row: T) => {
    if (onRowClick) {
      onRowClick(row);
    } else {
      // Default behavior - navigate to internal vulnerability page
      const cveId = row.cve || row.id;
      if (cveId) {
        // Use window.location for client-side navigation
        window.location.href = `/vulnerability?id=${encodeURIComponent(cveId)}`;
      }
    }
  };

  // Define filter presets
  const filterPresets = [
    { name: "Critical", filter: "critical" },
    { name: "High", filter: "high" },
    { name: "Medium", filter: "medium" },
    { name: "Low", filter: "low" },
  ];

  // Apply filter preset
  const applyFilterPreset = (filter: string) => {
    if (activeFilters.includes(filter)) {
      setActiveFilters(activeFilters.filter((f) => f !== filter));
      // Remove the filter logic here
      table.getColumn("severity")?.setFilterValue(undefined);
    } else {
      setActiveFilters([...activeFilters, filter]);
      // Apply the filter logic here
      table.getColumn("severity")?.setFilterValue(filter.toUpperCase());
    }
  };

  // Handle export
  const handleExport = (format: "csv" | "json") => {
    const selectedRows = table.getSelectedRowModel().rows;
    const dataToExport =
      selectedRows.length > 0 ? selectedRows.map((row) => row.original) : data;

    if (format === "csv") {
      // CSV export logic
      const headers = Object.keys(data[0] || {}).join(",");
      const csvRows = dataToExport.map((row) => Object.values(row).join(","));
      const csvContent = [headers, ...csvRows].join("\n");

      const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
      const url = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.setAttribute("href", url);
      link.setAttribute("download", "vulnerabilities.csv");
      link.click();
      setShowExportDropdown(false);
    } else if (format === "json") {
      // JSON export logic
      const jsonContent = JSON.stringify(dataToExport, null, 2);
      const blob = new Blob([jsonContent], { type: "application/json" });
      const url = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.setAttribute("href", url);
      link.setAttribute("download", "vulnerabilities.json");
      link.click();
      setShowExportDropdown(false);
    }
  };

  // Add a new function to handle report generation
  const handleGenerateReport = () => {
    const selectedRows = table
      .getSelectedRowModel()
      .rows.map((row) => row.original);
    if (selectedRows.length === 0) {
      // If no rows are selected, use all filtered rows
      selectedRows.push(
        ...table.getFilteredRowModel().rows.map((row) => row.original)
      );
    }

    if (onGenerateReport) {
      onGenerateReport(selectedRows);
    } else {
      // Default implementation if no callback provided
      generateDefaultReport(selectedRows);
    }
  };

  // Default report generation implementation
  const generateDefaultReport = (selectedData: T[]) => {
    // Create a formatted HTML report
    const dateStr = new Date().toISOString().split("T")[0];
    const reportTitle = `Vulnerability Report - ${dateStr}`;

    // Group vulnerabilities by severity for the summary
    const severityGroups: Record<string, number> = {};
    selectedData.forEach((item) => {
      const severity = (item.severity || "UNKNOWN").toUpperCase();
      severityGroups[severity] = (severityGroups[severity] || 0) + 1;
    });

    // Create HTML content
    let htmlContent = `
    <!DOCTYPE html>
    <html>
    <head>
      <title>${reportTitle}</title>
      <style>
        body { font-family: Arial, sans-serif; margin: 0; padding: 20px; color: #333; }
        h1 { color: #5b21b6; border-bottom: 1px solid #e5e7eb; padding-bottom: 10px; }
        .summary { background-color: #f9fafb; border-radius: 6px; padding: 15px; margin: 15px 0; }
        .summary h2 { margin-top: 0; font-size: 1.2rem; }
        table { width: 100%; border-collapse: collapse; margin: 20px 0; }
        th { background-color: #f3f4f6; text-align: left; padding: 10px; }
        td { padding: 10px; border-top: 1px solid #e5e7eb; }
        .critical { color: #dc2626; } 
        .high { color: #ea580c; }
        .medium { color: #ca8a04; }
        .low { color: #16a34a; }
        .severity-badge {
          display: inline-block;
          border-radius: 9999px;
          padding: 3px 8px;
          font-size: 12px;
          font-weight: 500;
        }
        .badge-critical { background-color: #fee2e2; color: #dc2626; }
        .badge-high { background-color: #ffedd5; color: #ea580c; }
        .badge-medium { background-color: #fef3c7; color: #ca8a04; }
        .badge-low { background-color: #dcfce7; color: #16a34a; }
        .badge-unknown { background-color: #e0f2fe; color: #0284c7; }
      </style>
    </head>
    <body>
      <h1>${reportTitle}</h1>
      
      <div class="summary">
        <h2>Executive Summary</h2>
        <p>This report contains ${selectedData.length} vulnerabilities found during security scanning.</p>
        <ul>
    `;

    // Add severity breakdown to summary
    for (const [severity, count] of Object.entries(severityGroups)) {
      const severityClass = severity.toLowerCase().includes("crit")
        ? "critical"
        : severity.toLowerCase().includes("high")
        ? "high"
        : severity.toLowerCase().includes("med")
        ? "medium"
        : severity.toLowerCase().includes("low")
        ? "low"
        : "";

      htmlContent += `<li class="${severityClass}">${count} ${
        severity.charAt(0) + severity.slice(1).toLowerCase()
      } vulnerabilities</li>`;
    }

    htmlContent += `
        </ul>
      </div>
      
      <h2>Detailed Findings</h2>
      <table>
        <thead>
          <tr>
            <th>Vulnerability ID</th>
            <th>Severity</th>
            <th>CVSS Score</th>
            <th>Affected Hosts</th>
            <th>Description</th>
          </tr>
        </thead>
        <tbody>
    `;

    // Add rows for each vulnerability
    selectedData.forEach((item) => {
      const severity = (item.severity || "UNKNOWN").toUpperCase();
      const severityClass = severity.toLowerCase().includes("crit")
        ? "badge-critical"
        : severity.toLowerCase().includes("high")
        ? "badge-high"
        : severity.toLowerCase().includes("med")
        ? "badge-medium"
        : severity.toLowerCase().includes("low")
        ? "badge-low"
        : "badge-unknown";

      const cvssScore =
        typeof item.cvss === "number"
          ? item.cvss.toFixed(1)
          : typeof item.riskScore === "number"
          ? item.riskScore.toFixed(1)
          : "?";

      const hostCount = Array.isArray(item.affectedHosts)
        ? item.affectedHosts.length
        : typeof item.count === "number"
        ? item.count
        : "?";

      htmlContent += `
        <tr>
          <td>${item.cve || item.id || "Unknown"}</td>
          <td><span class="severity-badge ${severityClass}">${
        severity.charAt(0) + severity.slice(1).toLowerCase()
      }</span></td>
          <td>${cvssScore}</td>
          <td>${hostCount}</td>
          <td>${item.description || "No description available"}</td>
        </tr>
      `;
    });

    htmlContent += `
        </tbody>
      </table>
      
      <div class="footer">
        <p>Report generated on ${new Date().toLocaleString()}</p>
      </div>
    </body>
    </html>
    `;

    // Create blob and download
    const blob = new Blob([htmlContent], { type: "text/html" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `vulnerability-report-${dateStr}.html`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  // Calculate summary of selected vulnerabilities
  const selectedVulnSummary = useMemo(() => {
    const selectedRows = table.getSelectedRowModel().rows;
    if (selectedRows.length === 0) return null;

    // Count by severity
    const severityCounts = {
      CRITICAL: 0,
      HIGH: 0,
      MEDIUM: 0,
      LOW: 0,
    };

    selectedRows.forEach((row) => {
      let severity = (row.original.severity || "").toUpperCase();

      // Normalize severity values
      if (severity.includes("CRIT")) severity = "CRITICAL";
      else if (severity.includes("HIGH")) severity = "HIGH";
      else if (severity.includes("MED")) severity = "MEDIUM";
      else if (severity.includes("LOW")) severity = "LOW";

      if (severity in severityCounts) {
        severityCounts[severity as keyof typeof severityCounts]++;
      }
    });

    return {
      count: selectedRows.length,
      severityCounts,
    };
  }, [table.getSelectedRowModel().rows]);

  return (
    <div className="w-full">
      {/* Search and Filter Controls */}
      <div className="mb-4 flex flex-col gap-4">
        <div className="flex items-center justify-between">
          <div className="flex items-center">
            <div className="relative">
              <svg
                className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"
                width="16"
                height="16"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              >
                <circle cx="11" cy="11" r="8"></circle>
                <path d="m21 21-4.3-4.3"></path>
              </svg>
              <input
                type="text"
                placeholder="Search vulnerabilities..."
                value={globalFilter}
                onChange={handleSearch}
                className="h-10 w-64 rounded-md border border-gray-200 bg-white px-10 text-sm focus:border-violet-500 focus:outline-none focus:ring-1 focus:ring-violet-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100"
              />
              {globalFilter && (
                <button
                  className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-500"
                  onClick={() => setGlobalFilter("")}
                >
                  <svg
                    width="16"
                    height="16"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  >
                    <line x1="18" y1="6" x2="6" y2="18"></line>
                    <line x1="6" y1="6" x2="18" y2="18"></line>
                  </svg>
                </button>
              )}
            </div>
            <div className="ml-4 text-sm text-gray-500">
              {table.getFilteredRowModel().rows.length} vulnerabilities found
            </div>
          </div>

          <div className="flex gap-2">
            <div className="relative" ref={exportRef}>
              <button
                className="flex items-center rounded-md border border-gray-200 px-3 py-1.5 text-sm dark:border-gray-700"
                onClick={() => setShowExportDropdown(!showExportDropdown)}
              >
                <Download className="mr-1.5 h-4 w-4" />
                Export
              </button>
              {showExportDropdown && (
                <div className="absolute right-0 top-full z-10 mt-1 w-36 rounded-md border border-gray-200 bg-white py-1 shadow-lg dark:border-gray-700 dark:bg-gray-800">
                  <button
                    className="w-full px-4 py-2 text-left text-sm hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700"
                    onClick={() => handleExport("csv")}
                  >
                    Export as CSV
                  </button>
                  <button
                    className="w-full px-4 py-2 text-left text-sm hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700"
                    onClick={() => handleExport("json")}
                  >
                    Export as JSON
                  </button>
                </div>
              )}
            </div>
          </div>
        </div>

        {/* Filter presets */}
        <div className="flex flex-wrap gap-2">
          {filterPresets.map((preset) => (
            <button
              key={preset.filter}
              onClick={() => applyFilterPreset(preset.filter)}
              className={cn(
                "rounded-full px-3 py-1 text-xs font-medium",
                activeFilters.includes(preset.filter)
                  ? "bg-violet-100 text-violet-800 dark:bg-violet-900/30 dark:text-violet-300"
                  : "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300"
              )}
            >
              {preset.name}
            </button>
          ))}
        </div>

        {/* Selected vulnerabilities summary */}
        {selectedVulnSummary && (
          <div className="rounded-md bg-violet-50 p-3 dark:bg-violet-900/10">
            <div className="flex items-center justify-between">
              <div>
                <span className="font-medium">
                  {selectedVulnSummary.count} vulnerabilities selected
                </span>
                <div className="mt-1 flex flex-wrap gap-3 text-sm">
                  {selectedVulnSummary.severityCounts.CRITICAL > 0 && (
                    <span className="text-red-600 dark:text-red-400">
                      {selectedVulnSummary.severityCounts.CRITICAL} Critical
                    </span>
                  )}
                  {selectedVulnSummary.severityCounts.HIGH > 0 && (
                    <span className="text-orange-600 dark:text-orange-400">
                      {selectedVulnSummary.severityCounts.HIGH} High
                    </span>
                  )}
                  {selectedVulnSummary.severityCounts.MEDIUM > 0 && (
                    <span className="text-yellow-600 dark:text-yellow-400">
                      {selectedVulnSummary.severityCounts.MEDIUM} Medium
                    </span>
                  )}
                  {selectedVulnSummary.severityCounts.LOW > 0 && (
                    <span className="text-green-600 dark:text-green-400">
                      {selectedVulnSummary.severityCounts.LOW} Low
                    </span>
                  )}
                </div>
              </div>
              <div className="flex gap-2">
                <button
                  onClick={handleGenerateReport}
                  className="rounded-md border border-violet-200 bg-violet-50 px-3 py-1 text-sm text-violet-700 hover:bg-violet-100 dark:border-violet-800 dark:bg-violet-900/20 dark:text-violet-300"
                >
                  Generate Report
                </button>
              </div>
            </div>
          </div>
        )}
      </div>

      {/* Table */}
      <div className="rounded-md border border-gray-200 dark:border-gray-700">
        <table className="w-full divide-y divide-gray-200 dark:divide-gray-700">
          <thead className="bg-gray-50 dark:bg-gray-800">
            {table.getHeaderGroups().map((headerGroup) => (
              <tr key={headerGroup.id}>
                {headerGroup.headers.map((header) => (
                  <th
                    key={header.id}
                    onClick={header.column.getToggleSortingHandler()}
                    className={cn(
                      "px-4 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100",
                      header.id !== "select" && "cursor-pointer"
                    )}
                  >
                    <div className="flex items-center gap-2">
                      {header.isPlaceholder
                        ? null
                        : flexRender(
                            header.column.columnDef.header,
                            header.getContext()
                          )}
                      {header.column.getCanSort() && (
                        <div
                          className={
                            header.column.getIsSorted()
                              ? "opacity-100"
                              : "opacity-0 group-hover:opacity-100"
                          }
                        >
                          {{
                            asc: (
                              <svg
                                width="14"
                                height="14"
                                viewBox="0 0 24 24"
                                fill="none"
                                stroke="currentColor"
                                strokeWidth="2"
                                strokeLinecap="round"
                                strokeLinejoin="round"
                              >
                                <path d="m5 15 7-7 7 7"></path>
                              </svg>
                            ),
                            desc: (
                              <svg
                                width="14"
                                height="14"
                                viewBox="0 0 24 24"
                                fill="none"
                                stroke="currentColor"
                                strokeWidth="2"
                                strokeLinecap="round"
                                strokeLinejoin="round"
                              >
                                <path d="m19 9-7 7-7-7"></path>
                              </svg>
                            ),
                          }[header.column.getIsSorted() as string] ?? null}
                        </div>
                      )}
                    </div>
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody className="divide-y divide-gray-200 dark:divide-gray-700">
            {table.getRowModel().rows.length ? (
              table.getRowModel().rows.map((row) => (
                <tr
                  key={row.id}
                  onClick={() => handleRowClick(row.original)}
                  className="cursor-pointer bg-white hover:bg-gray-50 dark:bg-gray-900 dark:hover:bg-gray-800"
                >
                  {row.getVisibleCells().map((cell) => (
                    <td
                      key={cell.id}
                      className="px-4 py-3 text-sm text-gray-900 dark:text-gray-100"
                      onClick={
                        cell.column.id === "select"
                          ? (e) => e.stopPropagation()
                          : undefined
                      }
                    >
                      {cell.column.id === "actions" ? (
                        <div className="flex items-center justify-end">
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              const cveId = row.original.cve || row.original.id;
                              if (cveId) {
                                window.open(
                                  `https://nvd.nist.gov/vuln/detail/${cveId}`,
                                  "_blank"
                                );
                              }
                            }}
                            className="rounded p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-500 dark:hover:bg-gray-800"
                            title="View in NIST NVD Database"
                          >
                            <div className="flex items-center">
                              <ExternalLink className="h-4 w-4" />
                              <span className="ml-1 text-xs">NVD</span>
                            </div>
                          </button>
                        </div>
                      ) : (
                        flexRender(
                          cell.column.columnDef.cell,
                          cell.getContext()
                        )
                      )}
                    </td>
                  ))}
                </tr>
              ))
            ) : (
              <tr>
                <td
                  colSpan={columnsWithSelection.length}
                  className="py-10 text-center text-gray-500"
                >
                  No vulnerabilities found
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>

      {/* Pagination */}
      <div className="mt-4 flex items-center justify-between">
        <div className="flex items-center gap-2">
          <select
            value={table.getState().pagination.pageSize}
            onChange={(e) => {
              table.setPageSize(Number(e.target.value));
            }}
            className="rounded-md border border-gray-200 bg-white px-2 py-1 text-sm dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200"
          >
            {[10, 20, 30, 40, 50].map((pageSize) => (
              <option key={pageSize} value={pageSize}>
                Show {pageSize}
              </option>
            ))}
          </select>
          <span className="text-sm text-gray-500">
            Showing{" "}
            {table.getState().pagination.pageIndex *
              table.getState().pagination.pageSize +
              1}{" "}
            to{" "}
            {Math.min(
              (table.getState().pagination.pageIndex + 1) *
                table.getState().pagination.pageSize,
              table.getFilteredRowModel().rows.length
            )}{" "}
            of {table.getFilteredRowModel().rows.length} vulnerabilities
          </span>
        </div>
        <div className="flex gap-2">
          <button
            className={cn(
              "rounded-md border border-gray-200 px-3 py-1 text-sm dark:border-gray-700",
              !table.getCanPreviousPage() && "cursor-not-allowed opacity-50"
            )}
            onClick={() => table.previousPage()}
            disabled={!table.getCanPreviousPage()}
          >
            Previous
          </button>
          {Array.from({ length: Math.min(5, table.getPageCount()) }, (_, i) => {
            const pageIndex = i;
            return (
              <button
                key={i}
                className={cn(
                  "rounded-md border px-3 py-1 text-sm",
                  table.getState().pagination.pageIndex === pageIndex
                    ? "border-violet-500 bg-violet-50 text-violet-700 dark:border-violet-800 dark:bg-violet-900/20 dark:text-violet-300"
                    : "border-gray-200 dark:border-gray-700"
                )}
                onClick={() => table.setPageIndex(pageIndex)}
              >
                {pageIndex + 1}
              </button>
            );
          })}
          <button
            className={cn(
              "rounded-md border border-gray-200 px-3 py-1 text-sm dark:border-gray-700",
              !table.getCanNextPage() && "cursor-not-allowed opacity-50"
            )}
            onClick={() => table.nextPage()}
            disabled={!table.getCanNextPage()}
          >
            Next
          </button>
        </div>
      </div>
    </div>
  );
}
